#include "EnemyManager.h"
#include "GeneralInclude.h"

CEnemyManager::CEnemyManager():EnemyTimer(0),ActualEnemyStartZone(0),ActualEnemyIndex(0)
{

}

CEnemyManager::~CEnemyManager()
{
	Destroy();
}

void CEnemyManager::Destroy()
{
	TimeManager->DeleteTimer(EnemyTimer);
	Enemies.DeleteListNodes();
	EnemiesGraph.DeleteListNodes();
	EnemyStartZones.DeleteListNodes();
}

void CEnemyManager::Start(u32 es)
{
    EnemySpeed = es;
    EnemyTimer = TimeManager->GetNewTimer();
    TimeManager->SetAndStartTimer(EnemyTimer,EnemySpeed);
}

void CEnemyManager::Load(stringc Level)
{
    s32 NumEnemies = ConfigManager->GetVarAsInt(Level,"NumEnemies");

    for (u32 i=0;i<(u32)NumEnemies;i++)
    {
        I2DNode *t = new I2DNode();
        stringc VarName;
        VarName = "Enemy" + UsefulFunctions->ConvertFromNumber(i);
        stringc File = ConfigManager->GetVarAsString(Level,VarName);
        t->LoadNode(File);
        t->GetSpriteNode()->SetVisible(false);
        EnemiesGraph.push_back(t);
    }

    u32 Round = 0;

    u32 Zones = ConfigManager->GetVarAsInt(Level,"eTotalZones");

    while (Round < Zones)
    {
        stringc VarName;
        EnemyZone *temp = new EnemyZone();

        VarName = "eZoneX_Begin_" + UsefulFunctions->ConvertFromNumber(Round);
        temp->Zone.Top.X = ConfigManager->GetVarAsInt(Level,VarName);
        VarName = "eZoneY_Begin_" + UsefulFunctions->ConvertFromNumber(Round);
        temp->Zone.Top.Y = ConfigManager->GetVarAsInt(Level,VarName);
        VarName = "eZoneX_End_" + UsefulFunctions->ConvertFromNumber(Round);
        temp->Zone.Down.X = ConfigManager->GetVarAsInt(Level,VarName);
        VarName = "eZoneY_End_" + UsefulFunctions->ConvertFromNumber(Round);
        temp->Zone.Down.Y = ConfigManager->GetVarAsInt(Level,VarName);
        VarName = "eNextX_" + UsefulFunctions->ConvertFromNumber(Round);
        temp->NextX = ConfigManager->GetVarAsInt(Level,VarName);
        VarName = "eNextY_" + UsefulFunctions->ConvertFromNumber(Round);
        temp->NextY = ConfigManager->GetVarAsInt(Level,VarName);

        EnemyStartZones.push_back(temp);
        Round++;
    }
}

bool CEnemyManager::Update(CBoard *board)
{
    if (EnemyTimer->IsEnded())
    {
        return AddNewEnemy(board);
    }
    return false;
}

void CEnemyManager::IncEnemySpeed(s32 ies)
{
	s32 es = (s32)EnemySpeed;
	if (es + ies >= 0)
		EnemySpeed += ies;

	pLogDebug << "EnemyManager::EnemySpeed is: " << EnemySpeed << endl;
}

bool CEnemyManager::AddNewEnemy(CBoard *board)
{
    CEnemy *enemy = new CEnemy();
    vector2du32 Pos = GetPosNewPosForEnemy();

	bool ret = UpdateEnemyZone(EnemyStartZones[ActualEnemyStartZone],board,Pos);

    UpdateIndexEnemy();
    s32 IDEnemy = GetIndexEnemy();
    SetEnemyGraph(enemy,(u32)IDEnemy);
    enemy->SetIndexEnemyType(IDEnemy);
    enemy->SetPosBoard(Pos);
    board->SetSizeBoardCell(&(enemy->GetEnemyGraph()));
    board->SetPosBoardCell(&(enemy->GetEnemyGraph()),Pos.X,Pos.Y);
    enemy->GetEnemyGraph().GetSpriteNode()->SetPositionZ(ENEMY_Z);
    Enemies.push_back(enemy);

    SceneManager->AddScalatorAnimator(enemy->GetEnemyGraph().GetSpriteNode(),
    vector3dvpos(enemy->GetEnemyGraph().GetSpriteNode()->GetScale() / 100.0),
    vector3dvpos(enemy->GetEnemyGraph().GetSpriteNode()->GetScale()),
    ENEMY_MOVEMENT_TIME - 10);

    I2DNode *temp = &(enemy->GetEnemyGraph());
    I2DSpriteSceneNode *temp2 = temp->GetSpriteNode();
    UpdateIndexActualZone();
    SceneManager->Sort();
//    SceneManager->DrawDebugNode(0);
	TimeManager->SetAndStartTimer(EnemyTimer,EnemySpeed);

	return ret;
}

bool CEnemyManager::UpdateEnemyZone(EnemyZone *enemyzone,CBoard *board,vector2du32 Pos)
{
	bool GameOver = false;

    for (std::list<CEnemy*>::iterator it=Enemies.begin();it!=Enemies.end();it++)
    {
		bool Move = false;

    	if (enemyzone->NextX != 0)
    	{
    		if ((*it)->GetPosBoard().Y == Pos.Y && enemyzone->Zone.IsPointInside((*it)->GetPosBoard()))
				Move = true;
    	}
    	else if (enemyzone->NextY != 0)
    	{
    		if ((*it)->GetPosBoard().X == Pos.X && enemyzone->Zone.IsPointInside((*it)->GetPosBoard()))
				Move = true;
    	}

    	if (Move)
		{
			if (MoveNextEnemy(*it,enemyzone,board))
				GameOver = true;
		}
    }

    return GameOver;
}

bool CEnemyManager::MoveNextEnemy(CEnemy *enemy,EnemyZone *enemyzone,CBoard *board)
{
    vector2du32 NextPos(enemy->GetPosBoard());
    NextPos.X += enemyzone->NextX;
    NextPos.Y += enemyzone->NextY;

    SceneManager->AddMoveAnimator(enemy->GetEnemyGraph().GetSpriteNode(),
    vector3dvpos(board->GetBoardXPosition(enemy->GetPosBoard().X),board->GetBoardYPosition(enemy->GetPosBoard().Y),ENEMY_Z),
    vector3dvpos(board->GetBoardXPosition(NextPos.X),board->GetBoardYPosition(NextPos.Y),ENEMY_Z),
    ENEMY_MOVEMENT_TIME - 10);


    board->SetPosBoardCell(&(enemy->GetEnemyGraph()),NextPos.X,NextPos.Y);
    enemy->SetPosBoard(vector2du32(NextPos.X,NextPos.Y));

    if (board->GetMoveQuad().IsPointInside(NextPos))
    {
    	// Start the trigger to game over.
    	return true;
    }

    return false;
}

vector2du32 CEnemyManager::GetPosNewPosForEnemy()
{
    vector2du32 ActualPos(EnemyStartZones[ActualEnemyStartZone]->Zone.Top);

	if (EnemyStartZones[ActualEnemyStartZone]->NextY != 0)
	{
		// To up or down quad.
		ActualPos.X = RandomGenerator->GetRandomNumber(EnemyStartZones[ActualEnemyStartZone]->Zone.Down.X+1,EnemyStartZones[ActualEnemyStartZone]->Zone.Top.X);
	}
	else if (EnemyStartZones[ActualEnemyStartZone]->NextX != 0)
	{
		// To left or right quad.
		ActualPos.Y = RandomGenerator->GetRandomNumber(EnemyStartZones[ActualEnemyStartZone]->Zone.Down.Y+1,EnemyStartZones[ActualEnemyStartZone]->Zone.Top.Y);
	}

	pLogDebug << "New Enemy at pos: (" << ActualPos.X << "," << ActualPos.Y << ")" << endl;
    return ActualPos;
}

void CEnemyManager::UpdateIndexActualZone()
{
    ActualEnemyStartZone++;
    if (ActualEnemyStartZone >= EnemyStartZones.size())
        ActualEnemyStartZone = 0;
}

void CEnemyManager::SetEnemyGraph(CEnemy *enemy,u32 Index)
{
    enemy->GetEnemyGraph().Clone(EnemiesGraph[Index]);
}

u32 CEnemyManager::GetIndexEnemy()
{
    return ActualEnemyIndex;
}

void CEnemyManager::UpdateIndexEnemy()
{
    ActualEnemyIndex = RandomGenerator->GetRandomNumber(EnemiesGraph.size());
}

bool CEnemyManager::DestroyEnemiesForFicha(CFicha *ficha,CBoard *board,vector2du32 *PosLast)
{
	vector2du32 ActualPos(ficha->GetPosX(),ficha->GetPosY());

	bool Exit = false;
	bool Found = false;

	do
	{
		switch (ficha->GetFichaHeading())
		{
			case FICHA_HEADING_LEFT:
			{
				(ActualPos.X)--;
			}
			break;

			case FICHA_HEADING_RIGHT:
			{
				(ActualPos.X)++;
			}
			break;

			case FICHA_HEADING_DOWN:
			{
				(ActualPos.Y)++;
			}
			break;

			case FICHA_HEADING_UP:
			{
				(ActualPos.Y)--;
			}
			break;
		}


		for (EnemiesList::iterator it=Enemies.begin();it!=Enemies.end();)
		{
			if ((*it)->GetPosBoard() == ActualPos)
			{
				*PosLast = ActualPos;
				Found = true;

				if (ficha->GetIDColor() == (*it)->GetIndexEnemyType())
				{
					EnemiesList::iterator it2 = it;
					it2++;
					Enemies.DeleteNode(*it);
					it = it2;
				}
				else
				{
					u32 IndexEnemy = (*it)->GetIndexEnemyType();
					(*it)->GetEnemyGraph().ChangeImage(EnemiesGraph[ficha->GetIDColor()]);
					(*it)->SetIndexEnemyType(ficha->GetIDColor());
					ficha->ChangeIDColor(IndexEnemy);
					return true;
				}
			}
			else
			{
				if (!Found && (ActualPos.X == 0 || ActualPos.Y == 0 || ActualPos.X == board->GetBoardLen().X || ActualPos.Y == board->GetBoardLen().Y))
					*PosLast = ActualPos;
				it++;
			}
		}

		Exit = (ActualPos.X > board->GetBoardLen().X || ActualPos.Y > board->GetBoardLen().Y);
	} while (!Exit);

	return false;
}
